package org.luxor.commons.elasticsearch;

import com.google.common.collect.Lists;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.RestStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Elastic 常用操作
 *
 * @author Mr.Yan  @date 2019/11/21
 */
public class ElasticClientRest {
    private static final Logger logger = LoggerFactory.getLogger(ElasticClientRest.class);

    public RestHighLevelClient rest;

    public ElasticClientRest(RestHighLevelClient rest) {
        this.rest = rest;
    }

    /**
     * 测试索引是否存在?
     *
     * @param index 索引名
     * @return true-已存在；false-不存在
     */
    public boolean indexExist(String index) throws ElasticsearchException {
        if (StringUtils.isEmpty(index)) {
            logger.error("index is null！");
            return false;
        }
        try {
            GetIndexRequest getIndexRequest = new GetIndexRequest(index);
            return rest.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            logger.error("测试 [{}] 索引是否存在时,出现异常", index);
            return false;
        }
    }

    /**
     * 查看集群中的全部索引
     *
     * @return 索引名称集合
     */
    public Map<String, Set<AliasMetaData>> indices() throws ElasticsearchException {
        try {
            GetAliasesRequest request = new GetAliasesRequest();
            GetAliasesResponse response = rest.indices().getAlias(request, RequestOptions.DEFAULT);
            if (RestStatus.OK.equals(response.status())) {
                if (response.getAliases() != null) {
                    return response.getAliases();
                }
            }
        } catch (IOException e) {
            logger.error("查看集群中的全部索引,出现异常", e);
        }
        return new HashMap<>(0);
    }

    /**
     * 测试ES网络连接
     *
     * @return @return true-网络通畅; false-网络不通
     */
    public boolean ping() throws ElasticsearchException {
        try {
            return rest.ping(RequestOptions.DEFAULT);
        } catch (IOException e) {
            logger.error("测试ES网络连接时,出现异常", e);
            return false;
        }
    }

    /**
     * 查看ES集群健康状况
     *
     * @return true-正常; false-异常
     */
    public boolean health() throws ElasticsearchException {
        try {
            ClusterHealthRequest request = new ClusterHealthRequest();
            ClusterHealthResponse response = rest.cluster().health(request, RequestOptions.DEFAULT);
            return ClusterHealthStatus.GREEN.equals(response.getStatus());
        } catch (IOException e) {
            logger.error("查看ES集群健康状况时,出现异常", e);
            return false;
        }
    }

    /**
     * 创建新索引
     *
     * @param index   索引名称
     * @param builder
     * @return
     * @throws ElasticsearchException
     */
    public boolean createIndex(String index, XContentBuilder builder) throws IOException, ElasticsearchException {
        try {
            GetIndexRequest getIndexRequest = new GetIndexRequest(index);
            boolean indexExists = rest.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            // 如果索引已存在
            if (indexExists) {
                logger.warn("{} 索引已经存在", index);
                return true;
            }
            // 创建新索引
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
            createIndexRequest.mapping(builder);
            AcknowledgedResponse createResponse = rest.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            if (createResponse.isAcknowledged()) {
                return true;
            }
            logger.error("创建 [{}] 索引失败", index);
        } catch (IOException e) {
            logger.error("创建 [{}] 索引时,出现异常", index, e);
        }
        return false;
    }


    /**
     * 修改索引的映射Mapping
     *
     * @param index   索引名称
     * @param builder 映射结构
     * @return
     * @throws ElasticsearchException
     */
    public boolean updateIndex(String index, XContentBuilder builder) throws ElasticsearchException {
        try {
            PutMappingRequest putMappingRequest = new PutMappingRequest(index);
            putMappingRequest.source(builder);
            AcknowledgedResponse putMappingResponse = rest.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
            if (putMappingResponse.isAcknowledged()) {
                return true;
            }
            logger.error("更新 [{}] 索引映射失败", index);
        } catch (IOException e) {
            logger.error("更新 [{}] 索引映射时,出现异常", index, e);
        }
        return false;
    }

    /**
     * 查看索引的映射Mapping
     *
     * @param index 索引名称
     * @return
     * @throws ElasticsearchException
     */
    public MappingMetaData getIndexMapping(String index) throws ElasticsearchException {
        if (StringUtils.isEmpty(index)) {
            logger.error("index is null！");
            return null;
        }
        try {
            GetMappingsRequest request = new GetMappingsRequest();
            request.indices(index);
            GetMappingsResponse response = rest.indices().getMapping(request, RequestOptions.DEFAULT);
            Map<String, MappingMetaData> mappings = response.mappings();
            if (!CollectionUtils.isEmpty(mappings)) {
                return response.mappings().get(index);
            }

        } catch (IOException e) {
            logger.error("查看某索引 [{}] 的Mapping映射时,出现异常", index, e);
        }
        return null;
    }

    /**
     * 删除某个索引
     *
     * @param index 索引名称
     * @return true-删除成功; false-删除失败
     * @throws ElasticsearchException
     */
    public boolean deleteIndex(String index) throws ElasticsearchException {
        if (StringUtils.isEmpty(index)) {
            logger.error("index is null！");
            return false;
        }
        try {
            GetIndexRequest getIndexRequest = new GetIndexRequest(index);
            boolean indexExists = rest.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            if (!indexExists) {
                return true;
            }

            DeleteIndexRequest request = new DeleteIndexRequest(index);
            AcknowledgedResponse acknowledgedResponse = rest.indices().delete(request, RequestOptions.DEFAULT);
            if (acknowledgedResponse.isAcknowledged()) {
                logger.info("删除 [{}] 索引成功", index);
                return true;
            }
            logger.error("删除 [{}] 索引失败", index);
        } catch (IOException e) {
            logger.error("删除 [{}] 索引时,出现异常", index, e);
        }
        return false;
    }


    /**
     * 测试分词器效果
     *
     * @param index 索引名
     * @param field 属性字段
     * @param text  待分析的语句
     * @return 分词结果
     */
    public List<String> getAnalyze(String index, String field, String... text) throws ElasticsearchException {
        if (StringUtils.isEmpty(index)) {
            logger.error("index is null！");
            return Lists.newArrayList();
        }
        if (StringUtils.isEmpty(field)) {
            logger.error("field is null！");
            return Lists.newArrayList();
        }
        if (text == null) {
            logger.error("text is null！");
            return Lists.newArrayList();
        }

        try {
            AnalyzeRequest request = AnalyzeRequest.withField(index, field, text);
            AnalyzeResponse response = rest.indices().analyze(request, RequestOptions.DEFAULT);
            List<AnalyzeResponse.AnalyzeToken> tokens = response.getTokens();
            if (!CollectionUtils.isEmpty(tokens)) {
                return tokens.stream().map(AnalyzeResponse.AnalyzeToken::getTerm).collect(Collectors.toList());
            }
        } catch (IOException e) {
            logger.error("测试分词器效果时,出现异常", e);
        }
        return Lists.newArrayList();
    }
}
